unit JATUIF_Driver_Screen;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, Video, contnrs, StrUtils, Mouse, Keyboard,
    JATUIF_Driver_Mouse, JATUIF_Driver_Keyboard;

type
    { TComponent }

    TComponent_cb_KeyPress = procedure(Key:Char) of Object;
    TComponent_cb_MouseEnter = procedure of Object;
    TComponent_cb_MouseLeave = procedure of Object;
    TComponent_Focus = procedure of Object;
    TComponent_UnFocus = procedure of Object;

    TComponent_Pos = record
      X : Integer;
      Y : Integer;
    end;

    { TComponent_Reg }

    TComponent_Reg = Class(TObject)
      Public
        TopLeft : TComponent_Pos;
        BottomRight : TComponent_Pos;
        cb_KeyPress : TComponent_cb_KeyPress;
        cb_MouseEnter : TComponent_cb_MouseEnter;
        cb_MouseLeave : TComponent_cb_MouseLeave;
        cb_Focus : TComponent_Focus;
        cb_UnFocus : TComponent_UnFocus;
        Constructor Create(x1,y1,x2,y2:Integer; cb_kp: TComponent_cb_KeyPress; cb_me: TComponent_cb_MouseEnter; cb_ml: TComponent_cb_MouseLeave; cb_fo: TComponent_Focus; cb_uf: TComponent_UnFocus);
    end;

    { TScreen }

    TScreen_Cursor = record
      X : Integer;
      Y : Integer;
    end;

    TMouse_Position = record
      X : Integer;
      Y : Integer;
    end;

    { TLayer }

    TLayer = class(TObject)
      Public
        Data : Array [1..80] of Array [1..25] of Char;
        Foreground : Array [1..80] of Array [1..25] of Byte;
        Background : Array [1..80] of Array [1..25] of Byte;
        Visible : Boolean;
        Constructor Create;
    end;

    TDataArray = Array [1..80] of Array [1..25] of Char;
    TColorArray = Array [1..8] of Array [1..25] of Byte;

    { TScreen }

    TScreen = Class(TObject)
      Public
        { Main Buffer }
        Buffer_Data : Array [1..80] of Array [1..25] of Char;
        Buffer_Foreground : Array[1..80] of Array [1..25] of Byte;
        Buffer_Background : Array[1..80] of Array [1..25] of Byte;

        { Constructor }
        Constructor Create(VModeOverride:Boolean);
        Constructor Create;

        { Drawing }
        Procedure DrawCharXY(C_Tag:Integer; X, Y: Integer; Character: Char; Foreground:Byte; Background:Byte);
        Procedure DrawChar(C_Tag:Integer; Character:Char; Foreground:Byte; Background:Byte);
        Procedure DrawXY(C_Tag:Integer; X,Y:Integer; Data:String; Foreground:Byte; Background:Byte);
        Procedure Draw(C_Tag:Integer; Data:String; Foreground:Byte; Background:Byte);

        { Security }
        Procedure LockUpdates;
        Procedure UnLockUpdates;

        { Cursor }
        Procedure SetCursorPosition(X,Y:Integer);
        Procedure GetCursorPosition(Var X:Integer; Var Y:Integer);

        { Event Handler }
        Procedure Eventize;
        Procedure Run;

        { Draw }
        Procedure Full_ReDraw;
        Procedure Force_ReDraw;
        Procedure Force_Area_ReDraw(X1,Y1,X2,Y2:Integer);

        { Clearing }
        Procedure ClearRegion(X1,Y1,X2,Y2:Integer);
        Procedure Clear;

        { Component }
        Function _Register(cx1, cy1, cx2, cy2: Integer; OnKeypress: TComponent_cb_KeyPress; OnMouseEnter: TComponent_cb_MouseEnter; OnMouseLeave: TComponent_cb_MouseLeave; OnFocus: TComponent_Focus; OnUnFocus: TComponent_UnFocus): Integer;
        Function _UnRegister(Tag:Integer):Boolean;
        Procedure BringToFront(Tag:Integer);
        Procedure SendToBack(Tag:Integer);
        Procedure BringForward(Tag:Integer);
        Procedure SendBackward(Tag:Integer);
        Procedure SetVisible(Tag:Integer; Visible:Boolean);
        Function IsVisible(Tag:Integer):Boolean;

        { Misc }
        Procedure ShowCursor(Show:Boolean);
        Procedure GetActiveScreen(var Active_Data : TDataArray; Var Active_Foreground : TColorArray; Var Active_Background : TColorArray);
        Procedure SetActiveScreen(Active_Data : TDataArray; Active_Foreground : TColorArray; Active_Background : TColorArray);
        Function GetLastClicked:Integer;
        Procedure Terminate;
        Procedure HardwareRelease;

        { Mouse }
        Function GetMouseX:Integer;
        Function GetMouseY:Integer;
      Private
        { Drivers }
        KeyboardDriver : TKeyboardDriver;
        MouseDriver : TMouseDriver;
        MousePosition : TMouse_Position;

        { Active Layer }
        Screen_Data : Array [1..80] of Array [1..25] of Char;
        Screen_Foreground : Array [1..80] of Array [1..25] of Byte;
        Screen_Background : Array [1..80] of Array [1..25] of Byte;

        { Buffered Layers }
        Component_Layer : TObjectList;

        { Screen Cursor}
        Cursor : TScreen_Cursor;
        Cursor_On : Boolean;

        { Component }
        Component_Tag : TStringList;
        Component_Reg : TObjectList;
        SendFocusedComponentKey : TComponent_cb_KeyPress;
        Last_Clicked : Integer;

        { Focus & Control }
        Component_Leave : TComponent_cb_MouseLeave;
        Component_UnFocus : TComponent_UnFocus;
        Focused_Tag : Integer;

        { Security }
        UpdatesLocked : Boolean;
        ScreenActive : Boolean;

        { Internal Callbacks }
        Procedure MouseDriver_Callback_Click(X,Y:Integer;Left:Boolean);
        Procedure MouseDriver_Callback_Move(X,Y:Integer);
        Procedure KeyboardDriver_Callback(Key:Char);
        Procedure _DummyKeyboardCallback(Key:Char);
        Procedure _DummyMouseMoveCallback;
        Procedure _DummyMouseClickCallback(X,Y:Integer; Left:Boolean);
        Procedure _DummyUnFocusCallback;
    end;

implementation

Procedure CursorOff;
Begin
     SetCursorType(crHidden);
end;

Procedure CursorOn;
Begin
     SetCursorType(crUnderline);
end;

function MakeWord(LoByte,HiByte:Byte):Word;
Type
    TMergedWord = packed record
      LoByte:Byte;
      HiByte:Byte;
    end;

Var
   MergedWord:TMergedWord;

Begin
     MergedWord.LoByte:=LoByte;
     MergedWord.HiByte:=HiByte;
     Result:= Word(MergedWord);
end;

{ TLayer }

constructor TLayer.Create;
Var
   i,n:Integer;

begin
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Data[n][i]:=#0;
             Foreground[n][i]:=15;
             Background[n][i]:=0;
         end;
     end;
     Visible:=True;
end;

{ TComponent }

Constructor TComponent_Reg.Create(x1,y1,x2,y2:Integer; cb_kp: TComponent_cb_KeyPress; cb_me: TComponent_cb_MouseEnter; cb_ml: TComponent_cb_MouseLeave; cb_fo: TComponent_Focus; cb_uf: TComponent_UnFocus);
begin
     TopLeft.X:= x1;
     TopLeft.Y:= y1;
     BottomRight.X:= x2;
     BottomRight.Y:= y2;
     cb_KeyPress:= cb_kp;
     cb_MouseEnter:= cb_me;
     cb_MouseLeave:= cb_ml;
     cb_Focus:= cb_fo;
     cb_UnFocus:= cb_uf;
end;

{ TScreen }

constructor TScreen.Create(VModeOverride:Boolean);
Var
   VMode:TVideoMode;

begin
     InitVideo;
     If VModeOverride then begin
        VMode.Col:=80;
        VMode.Row:=25;
        VMode.Color:=True;
        SetVideoMode(VMode);
     end;
     UpdatesLocked:= False;
     Focused_Tag:= -1;
     Component_Layer:= TObjectList.create(true);
     Component_Tag:= TStringList.Create;
     Component_Reg:= TObjectList.create(true);
     SendFocusedComponentKey:= @_DummyKeyboardCallback;
     Component_Leave:= @_DummyMouseMoveCallback;
     Component_UnFocus:= @_DummyUnFocusCallback;
     MouseDriver:= TMouseDriver.Create(@MouseDriver_Callback_Click, @MouseDriver_Callback_Move);
     KeyboardDriver:= TKeyboardDriver.Create(@KeyboardDriver_Callback);
     { Map Screen Region + 1 on Yto stop graphical glitches. }
     SetCursorPosition(1,1);
     CursorOff;
     Cursor_On:=False;
     Clear;
end;

Constructor TScreen.Create;
Begin
     Create(true);
end;

procedure TScreen.DrawCharXY(C_Tag:Integer; X, Y: Integer; Character: Char; Foreground:Byte; Background:Byte);
Var
   Layer:TLayer;
   aComponent:TComponent_Reg;
   Index:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(C_Tag));
     If Index = -1 then
        exit;
     Layer:= Component_Layer[Index] as TLayer;
     aComponent:= Component_Reg[Index] as TComponent_Reg;
     If (X >= aComponent.TopLeft.X) and (X <= aComponent.BottomRight.X) then begin
        If (Y >= aComponent.TopLeft.Y) and (Y <= aComponent.BottomRight.Y) then begin
           Layer.Data[X][Y]:= Character;
           Layer.Foreground[X][Y]:= Foreground;
           Layer.Background[X][Y]:= Background;
        end;
     end;
end;

procedure TScreen.DrawChar(C_Tag:Integer; Character:Char; Foreground:Byte; Background:Byte);
Var
   X:Integer = 0;
   Y:Integer = 0;
   Layer:TLayer;
   aComponent:TComponent_Reg;
   Index:Integer;

begin
     GetCursorPosition(X,Y);
     Index:= Component_Tag.IndexOf(IntToStr(C_Tag));
     If Index = -1 then
        exit;
     Layer:= Component_Layer[Index] as TLayer;
     aComponent:= Component_Reg[Index] as TComponent_Reg;
     If (X >= aComponent.TopLeft.X) and (X <= aComponent.BottomRight.X) then begin
        If (Y >= aComponent.TopLeft.Y) and (Y <= aComponent.BottomRight.Y) then begin
           Layer.Data[X][Y]:= Character;
           Layer.Foreground[X][Y]:= Foreground;
           Layer.Background[X][Y]:= Background;
        end;
     end;
end;

procedure TScreen.DrawXY(C_Tag:Integer; X,Y:Integer; Data:String; Foreground:Byte; Background:Byte);
Var
   i:integer;
   Layer:TLayer;
   aComponent:TComponent_Reg;
   Index:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(C_Tag));
     If Index = -1 then
        exit;
     Layer:= Component_Layer[Index] as TLayer;
     aComponent:= Component_Reg[Index] as TComponent_Reg;
     If (X >= aComponent.TopLeft.X) and (Y >= aComponent.TopLeft.Y) then begin
        If ((X+Length(Data)-1) <= aComponent.BottomRight.X) and (Y <= aComponent.BottomRight.Y) then begin
           For i:=1 to Length(Data) do begin
               If X+(i-1) < 80 then begin
                  Layer.Data[X+(i-1)][Y]:= Data[i];
                  Layer.Foreground[X+(i-1)][Y]:= Foreground;
                  Layer.Background[X+(i-1)][Y]:= Background;
               end;
           end;
        end;
     end;
end;

procedure TScreen.Draw(C_Tag:Integer; Data: String; Foreground:Byte; Background:Byte);
Var
   X:Integer = 0;
   Y:Integer = 0;
   I:Integer;
   Layer:TLayer;
   Index:Integer;
   aComponent:TComponent_Reg;

begin
     GetCursorPosition(X,Y);
     Index:= Component_Tag.IndexOf(IntToStr(C_Tag));
     If Index = -1 then
        exit;
     Layer:= Component_Layer[Index] as TLayer;
     aComponent:= Component_Reg[Index] as TComponent_Reg;
     If (X >= aComponent.TopLeft.X) and (Y >= aComponent.TopLeft.Y) then begin
        If ((X+Length(Data)-1) <= aComponent.BottomRight.X) and (Y <= aComponent.BottomRight.Y) then begin
           For i:=1 to Length(Data) do begin
               If X+(i-1) < 80 then begin
                  Layer.Data[X+(i-1)][Y]:= Data[i];
                  Layer.Foreground[X+(i-1)][Y]:= Foreground;
                  Layer.Background[X+(i-1)][Y]:= Background;
               end;
           end;
        end;
     end;
end;

procedure TScreen.LockUpdates;
begin
     Try
        UpdatesLocked:= True;
     Except

     end;
end;

procedure TScreen.UnLockUpdates;
begin
     Try
        UpdatesLocked:= False;
     Except

     end;
end;

procedure TScreen.SetCursorPosition(X, Y: Integer);
begin
     Cursor.X:= X;
     Cursor.Y:= Y;
     SetCursorPos(Cursor.X-1,Cursor.Y-1);
end;

procedure TScreen.GetCursorPosition(var X: Integer; var Y: Integer);
begin
     X:= Cursor.X;
     Y:= Cursor.Y;
end;

procedure TScreen.Eventize;
begin
     Full_ReDraw;
     Mousedriver.Poll;
     KeyboardDriver.Poll;
     sleep(5);
end;

procedure TScreen.Run;
begin
     ScreenActive:= True;
     While ScreenActive do begin
         Eventize;
     end;
end;

procedure TScreen.Full_ReDraw;
Var
   i,n,b,k:Integer;
   X:Integer = 0;
   Y:Integer = 0;
   Layer:TLayer;
   Updated:Boolean;
   Attr:Word;

begin
     If UpdatesLocked then
        Exit;
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Buffer_Data[n][i]:=' ';
             Buffer_Foreground[n][i]:= 15;
             Buffer_Background[n][i]:= 0;
         end;
     end;
     For b:=0 to Component_Layer.Count-1 do begin
         Layer:= Component_Layer[b] as TLayer;
         If Layer.Visible then begin
            For i:=1 to 25 do begin
                For n:=1 to 80 do begin
                    If Layer.Data[n][i] <> #0 then begin
                       If (Buffer_Data[n][i] <> Layer.Data[n][i]) or (Buffer_Foreground[n][i] <> Layer.Foreground[n][i]) or (Buffer_Background[n][i] <> Layer.Background[n][i]) then begin
                          Buffer_Data[n][i]:= Layer.Data[n][i];
                          Buffer_Foreground[n][i]:= Layer.Foreground[n][i];
                          Buffer_Background[n][i]:= Layer.Background[n][i];
                       end;
                    end;
                end;
            end;
         end;
     end;
     Updated:=False;
     k:=0;
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             If (Buffer_Data[n][i] <> Screen_Data[n][i]) or (Buffer_Foreground[n][i] <> Screen_Foreground[n][i]) or (Buffer_Background[n][i] <> Screen_Background[n][i]) then begin
                Screen_Data[n][i]:= Buffer_Data[n][i];
                Screen_Foreground[n][i]:= Buffer_Foreground[n][i];
                Screen_Background[n][i]:= Buffer_Background[n][i];
                Attr:= Screen_Foreground[n][i] + (Screen_Background[n][i] shl 4);
                Attr:= Attr;
                VideoBuf^[k]:= MakeWord(Ord(Screen_Data[n][i]), Attr);
                Updated:=True;
             end;
             inc(k);
         end;
     end;
     If Updated then begin
        UpdateScreen(true);
        If Cursor_On then
           CursorOn;
        GetCursorPosition(X,Y);
        SetCursorPosition(X,Y);
     end;
end;

procedure TScreen.Force_ReDraw;
Var
   i,n,b,k:Integer;
   X:Integer = 0;
   Y:Integer = 0;
   Layer:TLayer;
   Attr:Byte;

begin
     If UpdatesLocked then
        Exit;
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Buffer_Data[n][i]:=' ';
             Buffer_Foreground[n][i]:= 15;
             Buffer_Background[n][i]:= 0;
         end;
     end;
     For b:=0 to Component_Layer.Count-1 do begin
         Layer:= Component_Layer[b] as TLayer;
         If Layer.Visible then begin
            For i:=1 to 25 do begin
                For n:=1 to 80 do begin
                    If Layer.Data[n][i] <> #0 then begin
                       If (Buffer_Data[n][i] <> Layer.Data[n][i]) or (Buffer_Foreground[n][i] <> Layer.Foreground[n][i]) or (Buffer_Background[n][i] <> Layer.Background[n][i]) then begin
                          Buffer_Data[n][i]:= Layer.Data[n][i];
                          Buffer_Foreground[n][i]:= Layer.Foreground[n][i];
                          Buffer_Background[n][i]:= Layer.Background[n][i];
                       end;
                    end;
                end;
            end;
         end;
     end;
     k:=0;
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             If Buffer_Data[n][i] <> ' ' then begin
                Screen_Data[n][i]:= Buffer_Data[n][i];
                Screen_Foreground[n][i]:= Buffer_Foreground[n][i];
                Screen_Background[n][i]:= Buffer_Background[n][i];
                Attr:= Screen_Foreground[n][i] + (Screen_Background[n][i] shl 4);
                VideoBuf^[k]:= MakeWord(Ord(Screen_Data[n][i]),Attr);
             end;
             inc(k);
         end;
     end;
     UpdateScreen(true);
     GetCursorPosition(X,Y);
     SetCursorPosition(X,Y);
end;

procedure TScreen.Force_Area_ReDraw(X1, Y1, X2, Y2: Integer);
Var
   i,n,b,k:Integer;
   X:Integer = 0;
   Y:Integer = 0;
   Layer:TLayer;
   Attr:Byte;

begin
     If UpdatesLocked then
        Exit;
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Buffer_Data[n][i]:=' ';
             Buffer_Foreground[n][i]:= 15;
             Buffer_Background[n][i]:= 0;
         end;
     end;
     For b:=0 to Component_Layer.Count-1 do begin
         Layer:= Component_Layer[b] as TLayer;
         If Layer.Visible then begin
            For i:=1 to 25 do begin
                For n:=1 to 80 do begin
                    If Layer.Data[n][i] <> #0 then begin
                       If (Buffer_Data[n][i] <> Layer.Data[n][i]) or (Buffer_Foreground[n][i] <> Layer.Foreground[n][i]) or (Buffer_Background[n][i] <> Layer.Background[n][i]) then begin
                          Buffer_Data[n][i]:= Layer.Data[n][i];
                          Buffer_Foreground[n][i]:= Layer.Foreground[n][i];
                          Buffer_Background[n][i]:= Layer.Background[n][i];
                       end;
                    end;
                end;
            end;
         end;
     end;
     k:=0;
     For i:=Y1 to Y2 do begin
         For n:=X1 to X2 do begin
             If Buffer_Data[n][i] <> ' ' then begin
                Screen_Data[n][i]:= Buffer_Data[n][i];
                Screen_Foreground[n][i]:= Buffer_Foreground[n][i];
                Screen_Background[n][i]:= Buffer_Background[n][i];
                Attr:= Screen_Foreground[n][i] + (Screen_Background[n][i] shl 4);
                VideoBuf^[k]:=MakeWord(Ord(Screen_Data[n][i]),Attr);
             end;
             inc(k);
         end;
     end;
     UpdateScreen(true);
     GetCursorPosition(X,Y);
     SetCursorPosition(X,Y);
end;

procedure TScreen.ClearRegion(X1, Y1, X2, Y2:Integer);
Var
   i,n:Integer;
begin
     For i:=Y1 to Y2 do begin
         For n:=X1 to X2 do begin
             Buffer_Data[n][i]:=#0;
         end;
     end;
     Full_ReDraw;
end;

procedure TScreen.Clear;
Var
   i,n:Integer;

begin
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Buffer_Data[n][i]:=#32;
         end;
     end;
     Full_ReDraw;
end;

function TScreen._Register(cx1, cy1, cx2, cy2: Integer; OnKeypress: TComponent_cb_KeyPress; OnMouseEnter: TComponent_cb_MouseEnter; OnMouseLeave: TComponent_cb_MouseLeave; OnFocus: TComponent_Focus; OnUnFocus: TComponent_UnFocus): Integer;
Var
   LastID:Integer;
   NewID:Integer = 0;

begin
     LastID:= Random(5000);
     If Component_Tag.Count > 0 then
        LastID:= StrToInt(Component_Tag[Component_Tag.Count-1]);
     NewID:= LastID+1;
     Component_Tag.Add(IntToStr(NewID));
     Component_Reg.Add(TComponent_Reg.Create(cx1,cy1,cx2,cy2,OnKeypress, OnMouseEnter, OnMouseLeave, OnFocus, OnUnFocus));
     Component_Layer.Add(TLayer.Create);
     Result:= NewID;
end;

function TScreen._UnRegister(Tag: Integer): Boolean;
Var
   Index:Integer;

begin
     Result:=False;
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index <> -1 then begin
        Component_Tag.Delete(Index);
        Component_Reg.Delete(Index);
        Component_Layer.Delete(Index);
        Result:=True;
     End;
end;

procedure TScreen.BringToFront(Tag: Integer);
Var
   Index:Integer;
   i:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index = -1 then
        exit;
     While Index < Component_Tag.Count-1 do begin
         Component_Tag.Exchange(Index, Index+1);
         Component_Layer.Exchange(Index, Index+1);
         Component_Reg.Exchange(Index, Index+1);
         Index:= Component_Tag.IndexOf(IntToStr(Tag));
     end;
end;

procedure TScreen.SendToBack(Tag: Integer);
Var
   Index:Integer;
   i:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index = -1 then
        exit;
     While Index > 0 do begin
         Component_Tag.Exchange(Index, Index-1);
         Component_Layer.Exchange(Index, Index-1);
         Component_Reg.Exchange(Index, Index-1);
         Index:= Component_Tag.IndexOf(IntToStr(Tag));
     end;
end;

procedure TScreen.BringForward(Tag: Integer);
Var
   Index:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index = -1 then
        exit;
     If Index <> Component_Tag.Count-1 then begin
        Component_Tag.Exchange(Index, Index+1);
        Component_Layer.Exchange(Index, Index+1);
        Component_Reg.Exchange(Index, Index+1);
     end;
end;

procedure TScreen.SendBackward(Tag: Integer);
Var
   Index:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index = -1 then
        exit;
     If Index <> 0 then begin
        Component_Tag.Exchange(Index, Index-1);
        Component_Layer.Exchange(Index, Index-1);
        Component_Reg.Exchange(Index, Index-1);
     end;
end;

procedure TScreen.SetVisible(Tag: Integer; Visible: Boolean);
Var
   Layer:TLayer;
   Index:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index = -1 then
        Exit;
     Layer:= Component_Layer[Index] as TLayer;
     Layer.Visible:= Visible;
end;

function TScreen.IsVisible(Tag: Integer): Boolean;
Var
   Layer:TLayer;
   Index:Integer;

begin
     Index:= Component_Tag.IndexOf(IntToStr(Tag));
     If Index = -1 then
        Exit;
     Layer:= Component_Layer[Index] as TLayer;
     Result:= Layer.Visible;
end;

procedure TScreen.ShowCursor(Show: Boolean);
begin
     If Show then begin
        CursorOn;
        Cursor_On:=True;
     end else begin
         CursorOff;
         Cursor_On:=False;
     end;
end;

procedure TScreen.GetActiveScreen(var Active_Data: TDataArray; var Active_Foreground: TColorArray; var Active_Background: TColorArray);
Var
   i,n:Integer;

begin
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Active_Data[n][i]:= Screen_Data[n][i];
             Active_Foreground[n][i]:= Screen_Background[n][i];
             Active_Background[n][i]:= Screen_Foreground[n][i];
         end;
     end;
end;

procedure TScreen.SetActiveScreen(Active_Data: TDataArray; Active_Foreground: TColorArray; Active_Background: TColorArray);
Var
   i,n:Integer;

begin
     For i:=1 to 25 do begin
         For n:=1 to 80 do begin
             Screen_Data[n][i]:= Active_Data[n][i];
             Screen_Background[n][i]:= Active_Foreground[n][i];
             Screen_Foreground[n][i]:= Active_Background[n][i];
         end;
     end;
end;

function TScreen.GetLastClicked: Integer;
begin
     Result:= Last_Clicked;
end;

procedure TScreen.Terminate;
begin
     ScreenActive:= False;
end;

procedure TScreen.HardwareRelease;
begin
     DoneMouse;
     DoneKeyboard;
end;

function TScreen.GetMouseX: Integer;
begin
     Result:= MousePosition.X;
end;

function TScreen.GetMouseY: Integer;
begin
     Result:= MousePosition.Y;
end;

procedure TScreen.MouseDriver_Callback_Click(X, Y: Integer; Left: Boolean);
Var
   i:integer;
   Component:TComponent_Reg;
   Layer:TLayer;

begin
     If Left then begin
        i:=Component_Reg.Count;
        While i > 0 do begin
            Dec(i);
            Component:= Component_Reg[i] as TComponent_Reg;
            Layer:= Component_Layer[i] as TLayer;
            If Layer.Visible then begin
               If (X <= Component.BottomRight.X) and (Y <= Component.BottomRight.Y) and (X >= Component.TopLeft.X) and (Y >= Component.TopLeft.Y) then begin
                  Last_Clicked:= StrToInt(Component_Tag[i]);
                  ShowCursor(False);
                  Component_UnFocus;
                  SendFocusedComponentKey:= Component.cb_KeyPress;
                  Component_UnFocus:= Component.cb_UnFocus;
                  Component.cb_Focus;
                  exit;
               end;
            end;
        end;
     end;
     ShowCursor(False);
     Component_UnFocus;
     SendFocusedComponentKey:=@_DummyKeyboardCallback;
     Component_UnFocus:= @_DummyUnFocusCallback;
     Exit;
end;

procedure TScreen.MouseDriver_Callback_Move(X, Y: Integer);
Var
   i:integer;
   Component:TComponent_Reg;
   Layer:TLayer;
   Leave:Boolean;

begin
     Leave:=False;
     i:= Component_Reg.Count;
     MousePosition.X:=X;
     MousePosition.Y:=Y;
     While i > 0 do begin
         Dec(i);
         Component:= Component_Reg[i] as TComponent_Reg;
         Layer:= Component_Layer[i] as TLayer;
         If Layer.Visible then begin
            If (X <= Component.BottomRight.X) and (Y <= Component.BottomRight.Y) and (X >= Component.TopLeft.X) and (Y >= Component.TopLeft.Y) then begin
               If StrToInt(Component_Tag[i]) <> Focused_Tag then begin
                  Component_Leave;
                  Component.cb_MouseEnter;
                  Component_Leave:= Component.cb_MouseLeave;
                  Exit;
               end else begin
                   Exit;
               end;
            end;
         end;
     end;
     Focused_Tag:=-1;
     Component_Leave;
     Component_Leave:= @_DummyMouseMoveCallback;
end;

procedure TScreen.KeyboardDriver_Callback(Key: Char);
begin
     SendFocusedComponentKey(Key);
end;

procedure TScreen._DummyKeyboardCallback(Key: Char);
begin
     //Do Nothing.
end;

procedure TScreen._DummyMouseMoveCallback;
begin
     //Do Nothing.
end;

procedure TScreen._DummyMouseClickCallback(X, Y: Integer; Left: Boolean);
begin
     //Do Nothing.
end;

procedure TScreen._DummyUnFocusCallback;
begin
     //Do Nothing.
end;

end.

